﻿using UnityEngine;
using System;
using System.IO;
using System.Text;
using VoxelBlock.VoxelInput;


namespace VoxelBlock.VoxelInput
{
    public class VoxelInput
    {
        public static VoxelInputInfo GetVoxelData(byte[] var_Array_data)
        {
            if (var_Array_data[0] == 'V' && var_Array_data[1] == 'O' && var_Array_data[2] == 'X' && var_Array_data[3] == ' ')
            {
                return GetNewVoxelFileInfo(var_Array_data);
            }
            //byte[] var_Array_data = File.ReadAllBytes(a_Path);
            using (MemoryStream _ms = new MemoryStream(var_Array_data))
            {
                using (BinaryReader br = new BinaryReader(_ms))
                {
                    VoxelInputInfo newVoxelData = new VoxelInputInfo();
                    int SizeX, SizeY, SizeZ;
                    SizeX = br.ReadInt32();
                    SizeZ = br.ReadInt32();
                    SizeY = br.ReadInt32();
                    int MaxSize = SizeX * SizeY * SizeZ;
                    int[, ,] DataId = new int[SizeX, SizeY, SizeZ];
                    for (int x = 0; x < SizeX; x++)
                    {
                        for (int z = SizeZ - 1; z >= 0; z--)
                        {
                            for (int y = SizeY - 1; y >= 0; y--)
                            {
                                int data = br.ReadByte();
                                //if (data == 255)
                                //{
                                //    data = 0;
                                //}
                                //else
                                //{
                                //    data += 1;
                                //}
                                DataId[x, y, z] = data;
                            }
                        }
                    }
                    Color32[] Colors = new Color32[256];
                    for (int i = 0; i < 256; i++)
                    {
                        byte r = br.ReadByte();
                        byte g = br.ReadByte();
                        byte b = br.ReadByte();
                        byte R = (byte)(r * 4);
                        byte G = (byte)(g * 4);
                        byte B = (byte)(b * 4);
                        Color32 color = new Color32(R , G , B , 255);
                        Colors[i] = color;
                    }

                    newVoxelData.SizeX = SizeX;
                    newVoxelData.SizeY = SizeY;
                    newVoxelData.SizeZ = SizeZ;
                    newVoxelData.Version = new byte[] { 150, 0, 0, 0 };
                    newVoxelData.Colors = Colors;
                    newVoxelData.Voxels = DataId;
                    return newVoxelData;
                }
            }
        }

        public static VoxelInputInfo GetVoxelData(string a_Path)
        {
            byte[] var_Array_data = File.ReadAllBytes(a_Path);

            if (var_Array_data[0] == 'V' && var_Array_data[1] == 'O' && var_Array_data[2] == 'X' && var_Array_data[3] == ' ')
            {
                return GetNewVoxelFileInfo(var_Array_data);
            }

            using (MemoryStream _ms = new MemoryStream(var_Array_data))
            {
                using (BinaryReader br = new BinaryReader(_ms))
                {
                    VoxelInputInfo newVoxelData = new VoxelInputInfo();
                    int SizeX, SizeY, SizeZ;
                    SizeX = br.ReadInt32();
                    SizeZ = br.ReadInt32();
                    SizeY = br.ReadInt32();
                    int MaxSize = SizeX * SizeY * SizeZ;
                    int[,,] DataId = new int[SizeX, SizeY, SizeZ];
                    for (int x = 0; x < SizeX; x++)
                    {
                        for (int z = SizeZ - 1; z >= 0; z--)
                        {
                            for (int y = SizeY - 1; y >= 0; y--)
                            {
                                int data = br.ReadByte();
                                //if (data == 255)
                                //{
                                //    data = 0;
                                //}
                                //else
                                //{
                                //    data += 1;
                                //}
                                DataId[x, y, z] = data;
                            }
                        }
                    }
                    Color32[] Colors = new Color32[256];
                    for (int i = 0; i < 256; i++)
                    {
                        byte r = br.ReadByte();
                        byte g = br.ReadByte();
                        byte b = br.ReadByte();
                        byte R = (byte)(r * 4);
                        byte G = (byte)(g * 4);
                        byte B = (byte)(b * 4);
                        Color32 color = new Color32(R, G, B, 255);
                        Colors[i] = color;
                    }

                    newVoxelData.SizeX = SizeX;
                    newVoxelData.SizeY = SizeY;
                    newVoxelData.SizeZ = SizeZ;
                    newVoxelData.Version = new byte[] { 150, 0, 0, 0 };
                    newVoxelData.Colors = Colors;
                    newVoxelData.Voxels = DataId;
                    return newVoxelData;
                }
            }
        }


        public static VoxelInputInfo GetNewVoxelFileInfo(byte[] _data)
        {
            if (_data == null || _data.Length == 0)
            {
                return null;
            }
            //try
            //{
            using (MemoryStream _ms = new MemoryStream(_data))
            {
                using (BinaryReader br = new BinaryReader(_ms))
                {
                    VoxelInputInfo newVoxelFileInfo = new VoxelInputInfo();

                    // VOX_
                    br.ReadInt32();
                    // VERSION
                    newVoxelFileInfo.Version = br.ReadBytes(4);

                    byte[] _chunkId = br.ReadBytes(4);
                    string uuu = Encoding.Default.GetString(_chunkId);
                    //if (_chunkId[0] != 'M' || _chunkId[1] != 'A' || _chunkId[2] != 'I' || _chunkId[3] != 'N')
                    //{
                    //    Debug.LogError("Error main ID");
                    //    return null;
                    //}

                    //int _chunkSize = br.ReadInt32();

                    //br.ReadBytes(_chunkSize);

                    // SIZE
                    while (true)
                    {
                        byte chars = br.ReadByte();
                        if (chars == 'S')
                        {
                            chars = br.ReadByte();
                            chars = br.ReadByte();
                            chars = br.ReadByte();
                            break;
                        }
                    }
                    //_chunkId = br.ReadBytes(4);
                    //uuu = Encoding.Default.GetString(_chunkId);



                    br.ReadInt32();
                    br.ReadInt32();

                    //int SizeX, SizeY, SizeZ;
                    newVoxelFileInfo.SizeX = br.ReadInt32();
                    newVoxelFileInfo.SizeZ = br.ReadInt32();
                    newVoxelFileInfo.SizeY = br.ReadInt32();

                    // --- XYZI ---
                    _chunkId = br.ReadBytes(4);
                    uuu = Encoding.Default.GetString(_chunkId);
                    int VoxelNum = br.ReadInt32();
                    VoxelNum = br.ReadInt32();
                    VoxelNum = br.ReadInt32();
                    newVoxelFileInfo.Voxels = new int[newVoxelFileInfo.SizeX, newVoxelFileInfo.SizeY, newVoxelFileInfo.SizeZ];
                    for (int x = 0; x < newVoxelFileInfo.SizeX; x++)
                    {
                        for (int z = newVoxelFileInfo.SizeZ - 1; z >= 0; z--)
                        {
                            for (int y = newVoxelFileInfo.SizeY - 1; y >= 0; y--)
                            {
                                newVoxelFileInfo.Voxels[x, y, z] = 255;
                            }
                        }
                        //for (int z = 0; z < newVoxelFileInfo.SizeZ; z++)
                        //{
                        //    for (int y = 0; y < newVoxelFileInfo.SizeY; y++)
                        //    {
                        //        newVoxelFileInfo.Voxels[x,y,z] = 255;
                        //    }
                        //}
                    }
                    for (int i = 0; i < VoxelNum; i++)
                    {
                        int x = br.ReadByte();
                        int z = newVoxelFileInfo.SizeZ - br.ReadByte() - 1;
                        int y = br.ReadByte();
                        byte data = br.ReadByte();
                        if (data == 0)
                        {
                            data = 255;
                        }
                        else
                        {
                            data -= 1;
                        }
                        newVoxelFileInfo.Voxels[x, y, z] = data;
                    }

                    // --- RGBA ---
                    _chunkId = br.ReadBytes(4);
                    uuu = Encoding.Default.GetString(_chunkId);
                    br.ReadInt32();
                    br.ReadInt32();


                    Color32[] Colors = new Color32[256];
                    for (int i = 0; i < 256; i++)
                    {
                        byte r = br.ReadByte();
                        byte g = br.ReadByte();
                        byte b = br.ReadByte();
                        byte a = br.ReadByte();
                        int R = r / 4 * 4;
                        int G = g / 4 * 4;
                        int B = b / 4 * 4;
                        int A = a / 4 * 4;
                        Color32 color = new Color32((byte)R, (byte)G, (byte)B, 255);
                        Colors[i] = color;
                    }
                    newVoxelFileInfo.Colors = Colors;


                    return newVoxelFileInfo;
                }
            }

            //}
            //catch (System.Exception)
            //{
            //    return VoxelFileInfo.GetZero();
            //}
        }

        public static void SetVoxelData(VoxelInputInfo newVoxelData, string Path)
        {
            using (FileStream fs = new FileStream(Path, FileMode.Create))
            {
                using (System.IO.BinaryWriter br = new BinaryWriter(fs))
                {
                    int SizeX = newVoxelData.SizeX;
                    int SizeY = newVoxelData.SizeY;
                    int SizeZ = newVoxelData.SizeZ;

                    br.Write(newVoxelData.SizeX);
                    br.Write(newVoxelData.SizeZ);
                    br.Write(newVoxelData.SizeY);

                    int[, ,] DataId = newVoxelData.Voxels;
                    for (int x = 0; x < SizeX; x++)
                    {
                        for (int z = SizeZ - 1; z >= 0; z--)
                        {
                             for (int y = SizeY - 1; y >= 0; y--)
                             {
                                //if (DataId[x, y, z] != 255)
                                //{

                                //}
                                br.Write((byte)DataId[x, y, z]);
                            }
                        }
                    }

                    Color32[] Colors = newVoxelData.Colors;
                    for (int i = 0; i < 256; i++)
                    {
                        br.Write((byte)(Colors[i].r / 4));
                        br.Write((byte)(Colors[i].g / 4));
                        br.Write((byte)(Colors[i].b / 4));
                    }

                }
            }
        }


        public static byte[] SetVoxelData(VoxelInputInfo newVoxelData)
        {
            //System.BitConverter.GetBytes(newVoxelData.SizeX)

            int SizeX = newVoxelData.SizeX;
            int SizeY = newVoxelData.SizeY;
            int SizeZ = newVoxelData.SizeZ;
            byte[] allByte = new byte[12 + SizeX * SizeY * SizeZ + 256 * 3];
            int allByteIndex = 0;
            allByte[allByteIndex] = (byte)newVoxelData.SizeX;
            //Array.Copy(System.BitConverter.GetBytes(newVoxelData.SizeX), 0, allByte, allByteIndex, 4);
            allByteIndex += 4;
            //Array.Copy(System.BitConverter.GetBytes(newVoxelData.SizeZ), 0, allByte, allByteIndex, 4);
            allByte[allByteIndex] = (byte)newVoxelData.SizeZ;
            allByteIndex += 4;
            //Array.Copy(System.BitConverter.GetBytes(newVoxelData.SizeY), 0, allByte, allByteIndex, 4);
            allByte[allByteIndex] = (byte)newVoxelData.SizeY;
            allByteIndex += 4;

            int[,,] DataId = newVoxelData.Voxels;
            for (int x = 0; x < SizeX; x++)
            {
                for (int z = SizeZ - 1; z >= 0; z--)
                {
                    for (int y = SizeY - 1; y >= 0; y--)
                    {
                        //if (DataId[x, y, z] != 255)
                        //{
                        allByte[allByteIndex] = (byte)DataId[x, y, z];
                        allByteIndex++;
                        //}
                        //br.Write((byte)DataId[x, y, z]);
                    }
                }
            }

            Color32[] Colors = newVoxelData.Colors;
            for (int i = 0; i < 256; i++)
            {
                allByte[allByteIndex] = (byte)(Colors[i].r / 4);
                allByte[allByteIndex + 1] = (byte)(Colors[i].g / 4);
                allByte[allByteIndex + 2] = (byte)(Colors[i].b / 4);
                allByteIndex += 3;
            }
            return allByte;
        }


        public static byte[] SetVoxelDataOnlyVoxel(VoxelInputInfo newVoxelData)
        {
            //System.BitConverter.GetBytes(newVoxelData.SizeX)

            int SizeX = newVoxelData.SizeX;
            int SizeY = newVoxelData.SizeY;
            int SizeZ = newVoxelData.SizeZ;
            byte[] allByte = new byte[SizeX * SizeY * SizeZ];

            int[,,] DataId = newVoxelData.Voxels;
            int allByteIndex = 0;
            for (int x = 0; x < SizeX; x++)
            {
                for (int y = 0; y < SizeY; y++)
                {
                    for (int z = 0; z < SizeZ; z++)
                    {
                        allByte[allByteIndex] = (byte)DataId[x, y, z];
                        allByteIndex++;
                    }
                }
            }
            return allByte;
        }

    }
}
